﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using Athena.Objects;

namespace Athena.Plugins
{
    public partial class ReactionViewer : Athena.Tools.IGUITool
    {
        bool _Initializing = false;
        public override void SetupToolStrip(ToolStrip oStrip)
        {
            /*
            ToolStripButton oButton = new ToolStripButton();
            oButton.Text = Text;
            oButton.ToolTipText = "Reaction Editor";
            oButton.Click += new EventHandler(ShowHide_Click);
            oStrip.Items.Add(oButton);
             */ 
        }

        public override void SetupDockPanel(WeifenLuo.WinFormsUI.Docking.DockPanel oPanel)
        {
            this.DockPanel = oPanel;
            DockState = WeifenLuo.WinFormsUI.Docking.DockState.DockRight;
            Hide();
        }

        public override void ShowHide_Click(object sender, EventArgs e)
        {
            if (IsHidden)
            {                
                Show();                
            }
            else
            {
                Hide();
            }
        }

        public ReactionViewer()
        {
            InitializeComponent();

            SetStyle(ControlStyles.AllPaintingInWmPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw |
                ControlStyles.UserPaint, true);
            
            Text = "Reaction editor";
            _bHasContextMenuItems = true;
            _bHasMenuItems = false;
            _bRequiresNewToolWindow = false;
            ToolManager.Instance.RegisterTool(Text, this);
            if (!ToolManager.Instance.PropertyEditors.Contains(this))
                ToolManager.Instance.PropertyEditors.Add(this);

            CurrentModel.SelectionChanged += new Model.SelectionChangedDelegate(Model_SelectionChanged);
            CurrentModel.ModelChanged += new Model.ModelChangedDelegate(CurrentModel_ModelChanged);

            AvailableEquations = new List<Equation>();
        }

        void CurrentModel_ModelChanged(object sender, EventArgs e)
        {
            OnChange();
        }

        public override void SetupContextMenu(ToolStripMenuItem oStrip)
        {
            oStrip.Text = "Reaction editor...";
            oStrip.ToolTipText = "Provides a convenient way of changing properties of selected reaction";
            oStrip.Click += new EventHandler(oItem_Click);
        }

        void OnChange()
        {
            if (_Initializing) return;

            _Initializing = true;

            bool show = true;

            if (CurrentModel.Selected.Count < 1)
            {
                Hide();
                TargetReaction = null;
                show = false;
            }
            if (show)
                foreach (IDrawable id in CurrentModel.Selected)
                {
                    if (!(id is Connector))
                    {
                        Hide();
                        TargetReaction = null;
                        show = false;
                    }
                }

            if (show && CurrentModel.Selected.Count > 0)
            {
                bool allReactions = true;

                foreach (IDrawable id in CurrentModel.Selected)
                {
                    if (!(id is Connector))
                    {
                        allReactions = false;
                        break;
                    }
                }

                if (!allReactions)
                {
                    TargetReaction = null;
                    Hide();
                    show = false;
                }
            }
            if (show)
            {
                TargetReaction = CurrentModel.Selected[0] as Connector;
                if (IsHidden)
                    Show();

                if (CurrentModel.Selected.Count > 0)
                {
                    propertyGrid1.SelectedObjects = CurrentModel.Selected.ToArray();
                }
            }

            _Initializing = false;
        }

        public override void oItem_Click(object sender, EventArgs e)
        {
            OnChange();
        }

        public override bool Handles(List<Type> oTypes)
        {
            bool bResult = true;
            foreach (Type t in oTypes)
            {
                bResult &= Handles(t);
                if (!bResult) return false;
            }
            return bResult;
        }

        private bool Handles(Type t)
        {
            return (Utility.IsType(typeof(Connector), t));
        }

        public override void OnItemDoubleClick(HandledMouseEventArgs e)
        {
            OnChange();
            Refresh();
        }

        void Model_SelectionChanged(object sender, Model.SelectionEventArgs e)
        {
            if (!IsHidden)
                OnChange();
        }

        /// <summary>
        /// preformatted equations
        /// </summary>
        public class Equation
        {
            public static Core.Edge Reaction;
            public string RateExpression;
            public static ReactionViewer Rviewer;

            public class ParamPair
            {
                string _ID;
                double _Value;
                public string ID
                {
                    get { return _ID; }
                    set { _ID = value; }
                }
                public double Value
                {
                    get { return _Value; }
                    set 
                    { 
                        _Value = value;
                        if (Reaction != null)
                        {
                            HistoryManager.History.SetControllPoint("Parameter value changed : " + value);
                            Reaction.SetParameter(_ID, _Value);
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                        }
                    }
                }
                public ParamPair(string name, double value)
                {
                    _ID = name;
                    _Value = value;
                }
            }
            public class NodePair 
            {
                Equation _Equation;
                public NodePair(Equation eqn, string var, Core.Node node)
                {
                    _Equation = eqn;
                    _Variable = var;
                    _Node = node;
                }
                string _Variable;
                Core.Node _Node;
                public string Variable
                {
                    get { return _Variable; }
                    set { _Variable = value; } 
                }
                public string Actual
                {
                    get
                    {
                        if (_Node != null)
                            return _Node.ID;
                        return ""; 
                    }
                    set 
                    {
                        if (Reaction != null && Reaction.ParentModule != null)
                        {
                            Core.Item it = Reaction.ParentModule.FindItem(value);
                            if (it is Core.Node)
                                _Node = (Core.Node)it;
                            Rviewer.rateTextBox.Text = Reaction.Rate = _Equation.ActualRate;
                            if (Reaction.PossibleErrorInRate)
                                Utility.SetMessage("WARNING: rate expression is not a function of the reactants.");
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                        }
                    }
                }
            }
            public List<NodePair> Species = new List<NodePair>();
            public List<ParamPair> Parameters = new List<ParamPair>();
            public string ActualRate
            {
                get
                {
                    string rate = RateExpression;
                    if (rate.Contains("$reactants"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Reactants)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$reactants", inputs);
                    }
                    if (rate.Contains("$reactant"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Reactants)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$reactant", inputs);
                    }
                    if (rate.Contains("$Reactants"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Reactants)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$Reactants", inputs);
                    }
                    if (rate.Contains("$Reactant"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Reactants)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$Reactant", inputs);
                    }
                    if (rate.Contains("$products"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Products)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$products", inputs);
                    }
                    if (rate.Contains("$product"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Products)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$product", inputs);
                    }
                    if (rate.Contains("$Products"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Products)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$Products", inputs);
                    }
                    if (rate.Contains("$Product"))
                    {
                        string inputs = "";
                        foreach (Core.Node n in Reaction.Products)
                        {
                            inputs = inputs + "*" + n.ID;
                        }
                        inputs = inputs.Substring(1);
                        rate = rate.Replace("$Product", inputs);
                    }
                    foreach (NodePair p in Species)
                    {
                        if (!string.IsNullOrEmpty(p.Actual))
                            rate = rate.Replace(p.Variable, p.Actual);
                    }
                    return rate;
                }
            }
            public Equation(string expr)
            {
                RateExpression = expr;
            }
        }

        List<Equation> AvailableEquations = new List<Equation>();

        /// <summary>
        /// makes the list of available rate equations
        /// </summary>
        public void InitializeReactionList(string filename)
        {
            if (TargetReaction == null || !(TargetReaction.Item is Core.Edge)) return;
            try
            {
                availableRatesCmb.Items.Clear();
                AvailableEquations.Clear();

                Equation.Reaction = (Core.Edge)TargetReaction.Item;
                Equation.Rviewer = this;

                StreamReader reader = new StreamReader(new FileStream(filename, FileMode.Open));
                string line;
                while (!reader.EndOfStream)
                {
                    line = reader.ReadLine();
                    if (!string.IsNullOrEmpty(line.Trim()))
                    {
                        try
                        {
                            string[] split = line.Split(';');
                            string name = split[0].Trim(),
                                   rateexpr = split[1].Trim();
                            string[] species = split[2].Split(','),
                                     vars = split[3].Split(',');

                            Equation eqn = new Equation(rateexpr);
                            eqn.Species = new List<Equation.NodePair>(species.Length);
                            eqn.Parameters = new List<Equation.ParamPair>(vars.Length);


                            for (int i = 0; i < species.Length; ++i)
                            {
                                string s = species[i].Trim();
                                if (!string.IsNullOrEmpty(s))
                                {
                                    eqn.Species.Add(new Equation.NodePair(eqn, s, null));
                                }
                            }
                            for (int i = 0; i < vars.Length; ++i)
                            {
                                string s = vars[i].Trim();
                                if (!string.IsNullOrEmpty(s))
                                {
                                    eqn.Parameters.Add(new Equation.ParamPair(s, 1.0d));
                                }
                            }
                            AvailableEquations.Add(eqn);
                            availableRatesCmb.Items.Add(name);
                        }
                        catch (Exception)
                        {
                        }
                    }
                }
                availableRatesCmb.Items.Add("Make your own");
                reader.Close();
            }
            catch (Exception)
            {
                //file not found
            }
        }
        /// <summary>
        /// This class contains a name->Node pair. It is used by ReactionViewer to manipulate an edge
        /// </summary>
        public class Node : IComparable<Node>
        {
            public int CompareTo(Node other)
            {
                return ID.CompareTo(other.ID);
            }
            public ReactionViewer viewer;
            public Core.Node _Node;
            public enum Role { input, output, modifier };
            public Role _Role; 

            public string ID
            {
                get
                {
                    if (_Node == null)
                        return "";
                    else
                        return _Node.ID;
                }
                set
                {
                    if (_Node != null && value != _Node.ID)
                    {
                        HistoryManager.History.SetControllPoint("ID changed : " + value);
                        _Node.ID = value;
                        Utility.Refresh();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public double Stoichiometry
            {
                get
                {
                    if (viewer != null && viewer.TargetReaction != null && viewer.TargetReaction.Item is Core.Edge)
                    {
                        Core.Edge e = (Core.Edge)viewer.TargetReaction.Item;
                        switch (_Role)
                        {
                            case Role.input:
                                return e.GetReactantStoichiometry(_Node);
                            case Role.output:
                                return e.GetProductStoichiometry(_Node);
                            default:
                                return e.GetModifierStoichiometry(_Node);
                        }
                    }
                    return double.NaN;
                }
                set
                {
                    if (viewer != null && viewer.TargetReaction != null && viewer.TargetReaction.Item is Core.Edge)
                    {
                        Core.Edge e = (Core.Edge)viewer.TargetReaction.Item;
                        switch (_Role)
                        {
                            case Role.input:
                                e.SetReactantStoichiometry(_Node, value);
                                break;
                            case Role.output:
                                e.SetProductStoichiometry(_Node, value);
                                break;
                            default:
                                e.SetModifierStoichiometry(_Node,value);
                                break;
                        }
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public Node(Core.Node n, Role role, ReactionViewer rv) 
            { 
                _Node = n;
                viewer = rv;
                _Role = role;
            }
            public void Remove()
            {
                if (_Node != null)
                {
                    HistoryManager.History.SetControllPoint("Specied removed : " + _Node.ID);
                    if (viewer.TargetReaction != null)
                    {
                        viewer.TargetReaction.RemoveNode(_Node.Drawable);
                    }
                    CurrentModel.OnModelChanged(EventArgs.Empty);
                }
            }
        }
        /// <summary>
        /// This class contains a name->Parameter pair. It is used by ModuleViewer to manipulate an edge
        /// </summary>
        public class Parameter : IComparable<Parameter>
        {
            public int CompareTo(Parameter other)
            {
                return _ID.CompareTo(other._ID);
            }

            public ReactionViewer viewer;
            private string _ID;
            private Core.Parameter _Parameter;

            public string ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    if (viewer != null && viewer.TargetReaction != null && viewer.TargetReaction.Item is Core.Edge)
                    {
                        Core.Edge e = (Core.Edge)viewer.TargetReaction.Item;
                        if (e.ParentModule != null)
                        {
                            HistoryManager.History.SetControllPoint("Parameter ID changed : " + value);
                            e.ChangeParameterName(_ID, value);
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                        }
                    }
                }
            }
            public double Value
            {
                get
                {
                    if (_Parameter != null)
                        return _Parameter.Value;
                    else
                        return double.NaN;
                }
                set
                {
                    HistoryManager.History.SetControllPoint("Parameter value changed : " + value);
                    _Parameter.Value = value;
                    CurrentModel.OnModelChanged(EventArgs.Empty);
                }
            }

            public Parameter(string n, Core.Parameter parameter, ReactionViewer rxnviewer)
            {
                _ID = n;
                _Parameter = parameter;
                viewer = rxnviewer;
            }
        }
        private Connector _TargetReaction = null;
        public Connector TargetReaction
        {
            get { return _TargetReaction; }
            set
            {
                substWithCombo.Items.Clear();
                if (value != null && value.Item is Core.Edge)// && ((Core.Edge)value.Item).IsReaction)
                {
                    try
                    {
                        Core.Edge edge = (Core.Edge)value.Item;
                        _TargetReaction = value;
                        IDtextbox.Text = edge.ID;
                        rateTextBox.Text = edge.Rate;
                        InitializeAppearance();
                        InitializeReactionList(Utility.CurrentDirectory + "\\ReactionPlugin\\ratelaws.txt");
                        UpdateLists();

                        if (edge.ParentModule != null)
                        {
                            List<Core.Species> species = edge.ParentModule.LocalSpecies;
                            foreach (Core.Species s in species)
                                substWithCombo.Items.Add(s.ID);
                        }
                        if (((Core.Edge)value.Item).IsReaction)
                        {
                            availableRatesCmb.Show();
                            rate2TextBox.Show();
                            inputsDataGrid.Show();
                            outputsDataGrid.Show();
                            modifiersDataGrid.Show();
                            rateLabel.Text = "Reaction Rate:";
                        }
                        else
                        {
                            rate2TextBox.Hide();
                            availableRatesCmb.Hide();
                            inputsDataGrid.Hide();
                            outputsDataGrid.Hide();
                            modifiersDataGrid.Hide();
                            rateLabel.Text = "Regulation Rate:";
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
                else
                {
                    inputsDataGrid.DataSource = null;
                    outputsDataGrid.DataSource = null;
                    modifiersDataGrid.DataSource = null;
                    parametersDataGrid.DataSource = null;
                    parameters2DataGrid.DataSource = null;
                    IDtextbox.Text = "";
                    rate2TextBox.Text = "";
                    rateTextBox.Text = "";
                    substFromCombo.Items.Clear();
                    substWithCombo.Items.Clear();
                    //arrowListBox.Hide();
                    availableRatesCmb.Hide();
                    tabControl1.TabPages[0].Hide();
                    tabControl1.TabPages[1].Hide();
                    _TargetReaction = null;
                }
                if (value is BezierConnector)
                {
                    chkShowMiddle.Checked = ((BezierConnector)value).ShowMiddleSegment;
                    chkMakeStraight.Checked = ((BezierConnector)value).StraightLines;
                    chkLinkPoints.Checked = ((BezierConnector)value).LinkControlPoints;
                }
            }
        }

        public void UpdateLists()
        {
            try
            {
                if (_TargetReaction != null && (_TargetReaction.Item is Core.Edge))
                {
                    Core.Edge edge = (Core.Edge)_TargetReaction.Item;

                    List<Node> _Inputs = new List<Node>();
                    List<Node> _Outputs = new List<Node>();
                    List<Node> _Modifiers = new List<Node>();
                    List<Parameter> _Parameters = new List<Parameter>();

                    Hashtable inputs = edge.ReactantsHash,
                              outputs = edge.ProductsHash,
                              modifiers = edge.ModifiersHash,
                              parameters = edge.ParametersHash;

                    foreach (Core.Node n in inputs.Keys)
                    {
                        if (!(n == Core.Module.Empty))
                            _Inputs.Add(new Node(n, Node.Role.input, this));
                    }
                    foreach (Core.Node n in outputs.Keys)
                    {
                        if (!(n == Core.Module.Empty))
                            _Outputs.Add(new Node(n, Node.Role.output, this));
                    }
                    foreach (Core.Node n in modifiers.Keys)
                    {
                        _Modifiers.Add(new Node(n, Node.Role.modifier, this));
                    }
                    foreach (string s in parameters.Keys)
                    {
                        if (parameters[s] is Core.Parameter)
                            _Parameters.Add(new Parameter(s, (Core.Parameter)parameters[s], this));
                    }

                    _Inputs.Sort();
                    _Outputs.Sort();
                    _Modifiers.Sort();
                    _Parameters.Sort();

                    inputsDataGrid.DataSource = _Inputs;
                    outputsDataGrid.DataSource = _Outputs;
                    modifiersDataGrid.DataSource = _Modifiers;
                    parametersDataGrid.DataSource = _Parameters;
                    parameters2DataGrid.DataSource = _Parameters;

                    /*inputsDataGrid.Refresh();
                    outputsDataGrid.Refresh();
                    modifiersDataGrid.Refresh();
                    parametersDataGrid.Refresh();
                    parameters2DataGrid.Refresh();*/
                }
            }
            catch (Exception) { }
        }

        private void rateTextBox_TextChanged(object sender, EventArgs e)
        {
            if (!_Initializing && _TargetReaction != null && _TargetReaction is Connector)
            {
                _Initializing = true;
                HistoryManager.History.SetControllPoint("Rate changed : " + _TargetReaction.Name);
                ((Connector)_TargetReaction).Rate = rateTextBox.Text;
                if ((((Connector)_TargetReaction).Item is Core.Edge) &&
                    (((Core.Edge)_TargetReaction.Item).PossibleErrorInRate))
                    Utility.SetMessage("WARNING: rate expression is not a function of the reactants.");
                if (_TargetReaction is Objects.BezierConnector)
                {
                    ((Objects.BezierConnector)_TargetReaction).GenerateModifiers();
                }
                _Initializing = false;
                CurrentModel.OnModelChanged(EventArgs.Empty);                
            }
        }

        private void rate2TextBox_TextChanged(object sender, EventArgs e)
        {
            if (!_Initializing && _TargetReaction != null && _TargetReaction is Connector)
            {
                _Initializing = true;
                string rate = rate2TextBox.Text;
                HistoryManager.History.SetControllPoint("Rate changed : " + _TargetReaction.Name);
                ((Connector)_TargetReaction).Rate = rate;
                if ((((Connector)_TargetReaction).Item is Core.Edge) &&
                    (((Core.Edge)_TargetReaction.Item).PossibleErrorInRate))
                    Utility.SetMessage("WARNING: rate expression is not a function of the reactants.");
                if (_TargetReaction is Objects.BezierConnector)
                {
                    ((Objects.BezierConnector)_TargetReaction).GenerateModifiers();
                }
                _Initializing = false;
                CurrentModel.OnModelChanged(EventArgs.Empty);                
            }
        }

        #region Appearance

        public class ArrowHeadType
        {
            public static BezierConnector.ArrowHeadType _ArrowHead;
            public static BezierConnector.ArrowHeadType ArrowHead
            {
                get { return _ArrowHead; }
                set 
                {
                    HistoryManager.History.SetControllPoint("Arrow head changed");
                    _ArrowHead = value; 
                }
            }
        }

        public class ProcessDecorator
        {
            public static BezierConnector.ProcessDecorator _ProcessDecorator;
            public static BezierConnector.ProcessDecorator Decorator
            {
                get { return _ProcessDecorator; }
                set 
                {
                    HistoryManager.History.SetControllPoint("Reaction decorator changed");
                    _ProcessDecorator = value; 
                }
            }
        }

        private void InitializeAppearance()
        {
            try
            {
                //InitializeArrowHead();
                InitializeDecorators();
                if (CurrentModel.Selected != null && CurrentModel.Selected.Count > 0)
                {
                    foreach (IDrawable id in CurrentModel.Selected)
                    {
                        if (id is BezierConnector)
                        {
                            BezierConnector bezierConnector = (BezierConnector)id;

                            numericThickness.Value = (decimal)bezierConnector.Thickness;

                            numericGap.Value = (decimal)bezierConnector.CurveSegments[0].Distance;
                            break;
                        }
                    }
                }
            }
            catch (Exception) { }
        }
        /*
        private void InitializeArrowHead()
        {
            //BezierConnector.ArrowHeadType arrowType = Connector.ArrowHeadType.Arrow;
            if (CurrentModel.Selected != null && CurrentModel.Selected.Count > 0)
            {
                foreach (IDrawable id in CurrentModel.Selected)
                {
                    if (id is Connector)
                    {
                        ArrowHeadType.ArrowHead = ((Connector)id).ArrowHead;
                        break;
                    }
                }
            }
            List<BezierConnector.ArrowHeadType> list = new List<Connector.ArrowHeadType>();
            list.Add(ArrowHeadType.ArrowHead);
            //arrowDataGrid.DataSource = list;
            
        }*/

        private void InitializeDecorators()
        {
            cmbMiddle.Items.Clear();
            cmbMiddle.Items.Add(Athena.Objects.BezierConnector.ProcessDecorator.None.ToString());
            cmbMiddle.Items.Add(Athena.Objects.BezierConnector.ProcessDecorator.Empty.ToString());
            cmbMiddle.Items.Add(Athena.Objects.BezierConnector.ProcessDecorator.Omitted.ToString());
            cmbMiddle.Items.Add(Athena.Objects.BezierConnector.ProcessDecorator.Uncertain.ToString());
            cmbMiddle.Items.Add(Athena.Objects.BezierConnector.ProcessDecorator.Association.ToString());
            cmbMiddle.Items.Add(Athena.Objects.BezierConnector.ProcessDecorator.Dissociation.ToString());
        }

        private void colorButton_Click(object sender, EventArgs e)
        {
            if (CurrentModel.Selected == null) return;

            colorDialog.ShowDialog();

            HistoryManager.History.SetControllPoint("Connector(s) color changed");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is Connector)
                {
                    ((Connector)id).ColorStart = colorDialog.Color;
                    ((Connector)id).ColorEnd = colorDialog.Color;
                }
            }
            Utility.Refresh();
        }

        private void chkMakeStraight_CheckedChanged(object sender, EventArgs e)
        {
            if (CurrentModel.Selected == null || CurrentModel.Selected.Count < 1) return;

            HistoryManager.History.SetControllPoint("Connector(s) shape changed");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                {
                    BezierConnector bezierConnector = (BezierConnector)id;
                    bezierConnector.SelectAllSegments();
                    if (bezierConnector.StraightLines != chkMakeStraight.Checked)
                        bezierConnector.StraightLines = chkMakeStraight.Checked;
                }
            }
            Utility.Refresh();

        }

        private void chkShowMiddle_CheckedChanged(object sender, EventArgs e)
        {
            if (CurrentModel.Selected == null || CurrentModel.Selected.Count < 1) return;

            HistoryManager.History.SetControllPoint("Connector(s) shape changed");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                {
                    BezierConnector bezierConnector = (BezierConnector)id;
                    if (bezierConnector.ShowMiddleSegment != chkShowMiddle.Checked)
                        bezierConnector.ShowMiddleSegment = chkShowMiddle.Checked;
                }
            }
            Utility.Refresh();
        }

        private void txtDistanceStart_TextChanged(object sender, EventArgs e)
        {
            if (CurrentModel.Selected == null || CurrentModel.Selected.Count < 1) return;

            float fStart = 0.0f;
            try
            {
                fStart = (float)(numericGap.Value);
            }
            catch
            {
                return;
            }

            HistoryManager.History.SetControllPoint("Connector(s) shape changed");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                {
                    BezierConnector bezierConnector = (BezierConnector)id;

                    foreach (BezierConnector.CurveSegment segment in bezierConnector.CurveSegments)
                    {
                        segment.Distance = fStart;
                        segment.CleanUpDiagram();
                    }
                }
            }
            Utility.Refresh();

        }

        private void thickness_TextChanged(object sender, EventArgs e)
        {
            float fthickness = 0.0f;
            try
            {
                fthickness = (float)numericThickness.Value;
            }
            catch
            {
                return;
            }

            HistoryManager.History.SetControllPoint("Connector(s) shape changed");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                {
                    ((BezierConnector)id).Thickness = fthickness;
                    ((BezierConnector)id).SelectedThickness = fthickness;
                }
            }
            Utility.Refresh();
        }
        private void arrowListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            HistoryManager.History.SetControllPoint("Connector(s) shape changed");

            BezierConnector.ArrowHeadType arrowHead = Connector.ArrowHeadType.Arrow;

            switch (arrowListBox.SelectedIndex)
            {
                case 0:
                    arrowHead = Connector.ArrowHeadType.Arrow;
                    break;
                case 1:
                    arrowHead = Connector.ArrowHeadType.Circle;
                    break;
                case 3:
                    arrowHead = Connector.ArrowHeadType.Stimulation;
                    break;
                case 4:
                    arrowHead = Connector.ArrowHeadType.Modulation;
                    break;
                case 5:
                    arrowHead = Connector.ArrowHeadType.Trigger;
                    break;
                case 6:
                    arrowHead = Connector.ArrowHeadType.None;
                    break;
                case 2:
                default:
                    arrowHead = Connector.ArrowHeadType.Bar;
                    break;
            }

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                {
                    BezierConnector bz = (BezierConnector)id;
                    if (bz.IsRegulation)
                        if (arrowHead == Connector.ArrowHeadType.Arrow)
                            ((BezierConnector)id).ArrowHead = Connector.ArrowHeadType.Circle;
                        else
                            ((BezierConnector)id).ArrowHead = arrowHead;
                    else
                        ((BezierConnector)id).ArrowHead = BezierConnector.ArrowHeadType.Arrow;
                }
            }

            Utility.Refresh();
        }

        private void cmbMiddle_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (CurrentModel.Selected == null || CurrentModel.Selected.Count < 1) return;

            HistoryManager.History.SetControllPoint("Connector(s) decorator(s) changed");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                {
                    BezierConnector bezierConnector = (BezierConnector)id;
                    bezierConnector.MiddleDecorator = (BezierConnector.ProcessDecorator)Enum.Parse(typeof(BezierConnector.ProcessDecorator), (string)cmbMiddle.SelectedItem);
                }
            }
            Utility.Refresh();
        }

        #endregion

        List<Label> NodeLabels = new List<Label>();
        private void availableRatesCmb_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_TargetReaction == null || _TargetReaction.Item == null) return;

            Equation eqn;
            if (availableRatesCmb.SelectedIndex == availableRatesCmb.Items.Count - 1)
            {
                CustomnReactionWindow window = new CustomnReactionWindow();
                window.Show();
                InitializeReactionList(Utility.CurrentDirectory + "\\ReactionPlugin\\ratelaws.txt");
                eqn = AvailableEquations[availableRatesCmb.Items.Count - 2];
            }
            else
            {
                if (AvailableEquations.Count <= availableRatesCmb.SelectedIndex)
                    return;
                eqn = AvailableEquations[availableRatesCmb.SelectedIndex];
            }

            substFromCombo.Items.Clear();

            foreach (Equation.NodePair np in eqn.Species)
                substFromCombo.Items.Add(np.Variable);
            
            rate2TextBox.Text = eqn.ActualRate;
            //speciesDataGrid.DataSource = eqn.Species;
            Point location = groupBox6.Location;
            foreach (Label l in NodeLabels)
            {
                tabControl1.TabPages[1].Controls.Remove(l);
            }
            NodeLabels.Clear();
            foreach (Equation.NodePair np in eqn.Species)
            {
                Label l = new Label();
                l.Location = location;
                location.Y += 10;
                l.Text = np.Variable;
                NodeLabels.Add(l);
                tabControl1.TabPages[1].Controls.Add(l);
            }
            tabControl1.Refresh();
            //parameters2DataGrid.DataSource = eqn.Parameters;
            //HistoryManager.History.SetControllPoint("Rate changed:" + _TargetReaction.ID);
            _TargetReaction.Rate = eqn.ActualRate;
            if ((_TargetReaction.Item is Core.Edge) &&
                    (((Core.Edge)_TargetReaction.Item).PossibleErrorInRate))
                Utility.SetMessage("WARNING: rate expression is not a function of the reactants.");
            rateTextBox.Text = eqn.ActualRate;
            //CurrentModel.OnModelChanged(EventArgs.Empty);
        }

        private void IDtextbox_TextChanged(object sender, EventArgs e)
        {
            if (_Initializing || TargetReaction != null && !string.IsNullOrEmpty(IDtextbox.Text))
            {
                _Initializing = true;
                TargetReaction.Name = IDtextbox.Text;
                Utility.Refresh();
                _Initializing = false;
            }
        }

        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_TargetReaction == null || _Initializing) return;
            _Initializing = true;
            if (substWithCombo.SelectedIndex >= 0 && substFromCombo.SelectedIndex >= 0)
            {
                string s1 = substFromCombo.SelectedItem as string;
                string s2 = substWithCombo.SelectedItem as string;
                if (s1 != null && s2 != null)
                {
                    HistoryManager.History.SetControllPoint("Rate Changed:" + _TargetReaction.Name);
                    _TargetReaction.Rate = rate2TextBox.Text.Replace(s1, s2);
                    if ((_TargetReaction.Item is Core.Edge) &&
                        (((Core.Edge)_TargetReaction.Item).PossibleErrorInRate))
                            Utility.SetMessage("WARNING: rate expression is not a function of the reactants.");
                    CurrentModel.OnModelChanged(EventArgs.Empty);
                }
            }
            _Initializing = true;
        }
        
        private void newControlPointButton_Click(object sender, EventArgs e)
        {
            HistoryManager.History.SetControllPoint("Insert Break Point");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                    ((BezierConnector)id).InsertLineBreaks = true;
            }
            //Utility.Refresh();
        }

        private void dataView_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            Utility.SetMessage("Error in value");
            e.Cancel = true;
        }

        /// <summary>
        /// Prevent some nasty keys ...
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (!Focused) return false;

            switch (keyData)
            {
                case Keys.Up:
                case Keys.Down:
                case Keys.Back:
                case Keys.Tab:
                case Keys.Enter:
                case Keys.Home:
                case Keys.Home & Keys.Shift:
                    return true;

                default:
                    return base.ProcessCmdKey(ref msg, keyData);
            }
        }

        private void chkLinkPoints_CheckedChanged(object sender, EventArgs e)
        {
            HistoryManager.History.SetControllPoint("Link control points");

            foreach (IDrawable id in CurrentModel.Selected)
            {
                if (id is BezierConnector)
                    ((BezierConnector)id).LinkControlPoints = chkLinkPoints.Checked;
            }

            Utility.Refresh();
        }

        private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            HistoryManager.History.SetControllPoint("property changed");
            CurrentModel.OnModelChanged(EventArgs.Empty);
            Utility.Refresh();
        }

        
    }
}

